<?php
exists_frame();
//调度器
final class XScheduler extends XObject {
    private $app_instance;
    private $app_method;
    private $cfg;
    public function __construct() {
        if(version_compare(PHP_VERSION,'5.3.0') < 0) {
            throw new XException('XPHPFramework need run in php varsion lagre 5.3.0, your php version is'.PHP_VERSION);
        }
        define('PHP_CLI',PHP_SAPI =='cli');
        $this->load_cfg();
        $this->set_time_zone();
        if(PHP_CLI) {
            return new XServer($this);
        } else {
            $this->load_app();
        }
    }
    public function load_app() {
        $this->define_env_constanst();
        $this->load_application_class_file();
    }
    private function define_env_constanst() {
        define('__X_URI__',strtolower($_SERVER['REQUEST_URI']));
        if(($pos = strpos(__X_URI__,'?')) !== false) {
            $uri_path = substr(__X_URI__,0,$pos);
            $query_string = substr(__X_URI__,$pos+1);
        } else {
            $uri_path = __X_URI__;
        
        }
        if($this->cfg->uri_mode == 1 && isset($query_string)) {
            $_GET['a'] = empty($_GET['a']) ? '':$_GET['a'];
            $uri_path = dirname($_GET['a']);
            $call_page_func = basename($_GET['a']);
        } else if($this->cfg->uri_mode == 2) { //PATH_INFO mode
            if(empty($_SERVER['PATH_INFO'])) {
                $_SERVER['PATH_INFO'] = str_replace('/'.basename($_SERVER['SCRIPT_FILENAME']),'',$_SERVER['PHP_SELF']);
            }
            $uri_path = dirname($_SERVER['PATH_INFO']);
            $call_page_func = basename($_SERVER['PATH_INFO']);
            if(empty($_SERVER['PATH_INFO'])) $call_page_func = basename($_SERVER['PHP_SELF'],$this->cfg->url_file_suffix);
        } else {
            $uri_path = dirname($uri_path);
            $call_page_func = basename($_SERVER['PHP_SELF'],$this->cfg->url_file_suffix);
        }
        define('__X_WEB_ROOT__',dirname($_SERVER['SCRIPT_FILENAME']));
        defined('__X_APP_ROOT__') || define('__X_APP_ROOT__',__X_WEB_ROOT__);
        $call_page_name = basename($uri_path);
        if($uri_path != '/') {
            $uri_path = dirname($uri_path) == '/' ? '' : dirname($uri_path);
            define('__X_CALL_PAGE_DIR__',__X_APP_ROOT__."/{$this->cfg->php_dir_name}$uri_path");
        } else {
            define('__X_CALL_PAGE_DIR__',__X_APP_ROOT__."/{$this->cfg->php_dir_name}");
        }
        $request_method = empty($_SERVER['REQUEST_METHOD']) ? 'g' : substr(strtolower($_SERVER['REQUEST_METHOD']),0,1);
        $add_sub_domain_path = '';
        if($this->cfg->subsite_mode > 0) {
            if($this->cfg->subsite_mode < $this->cfg->subsite_start_level) {
                throw new XException('subsite_start_level not be greater than subsite_mode in your confingure file');
            }
            if($_SERVER['SERVER_ADDR'] != $_SERVER['HTTP_HOST']) {
                if(empty($_SERVER['HTTP_HOST'])) {
                    $_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'];
                }
                $sub_domain_list  = explode('.',$_SERVER['HTTP_HOST']);
                $sub_domain_list = array_reverse($sub_domain_list);
                $sub_domain_list_count = count($sub_domain_list) -1;
                if($sub_domain_list_count >= $this->cfg->subsite_start_level) {
                    for($i=$this->cfg->subsite_start_level;$i<=$this->cfg->subsite_mode;$i++) {
                        $add_sub_domain_path = "{$sub_domain_list[$i]}/{$add_sub_domain_path}";
                    }
                }
            }
        }
        if(trim($call_page_name)=='') {
            define('__X_CALL_PAGE_FILE__',__X_CALL_PAGE_DIR__."/{$add_sub_domain_path}{$call_page_func}.php");
            define('__X_CALL_PAGE_NAME__',$call_page_func);
        } else {
            define('__X_CALL_PAGE_FILE__',__X_CALL_PAGE_DIR__. "/{$add_sub_domain_path}{$call_page_name}.php");
            define('__X_CALL_PAGE_NAME__',$call_page_name);
        }
        define('__X_CALL_PAGE_FUNC__',$request_method.$call_page_func);
        define('__X_APP_DATA_DIR__',__X_APP_ROOT__."/{$this->cfg->data_dir_name}");
        define('__X_APP_UI_DIR__',__X_APP_ROOT__."/{$this->cfg->ui_dir_name}");
        define('__X_APP_PHP_ERROR_LOG__',__X_APP_DATA_DIR__."/{$this->cfg->error_log_dir}/".date('Ymd'));
    }
    public function load_application_class_file() {
        if(!file_exists(__X_CALL_PAGE_FILE__)) {
            throw new XException('File '.__X_CALL_PAGE_FILE__.' not be found');
        }
        include_once(__X_CALL_PAGE_FILE__);
        if(!class_exists(__X_CALL_PAGE_NAME__,false)) {
            throw new XException('Class '.__X_CALL_PAGE_NAME__.' not be found');
        }
        $classname = __X_CALL_PAGE_NAME__;
        $method = __X_CALL_PAGE_FUNC__;
        $ref = new ReflectionClass(__X_CALL_PAGE_NAME__);
        $call_method = $ref->hasMethod(__X_CALL_PAGE_FUNC__);
        if($call_method === false) {
            throw new XException('Class '.__X_CALL_PAGE_NAME__.' method '.__X_CALL_PAGE_FUNC__.' not be found');
        }
        $call_method = $ref->getMethod(__X_CALL_PAGE_FUNC__);
        if($call_method->isDestructor()) {
            throw new XException('Can not call destruct method');
        }
        if($call_method->isPrivate() || $call_method->isProtected()) {
            throw new XException('Class '.__X_CALL_PAGE_NAME__.' method '.__X_CALL_PAGE_FUNC__.' is private or protected');
        }
        $refX = $ref->getParentClass();
        if($refX === false || $refX->getName() != 'X') {
            throw new XException("class $classname need extends XPHPFramework of class X");
        }
        $this->app_instance = $ref->newInstance();
        if($call_method->isConstructor() && $this->app_instance->initStat === false) {
            throw new XException('because class '.__X_CALL_PAGE_FUNC__.' defined constructor , so need call to $this->call_init() within method '.__X_CALL_PAGE_FUNC__.' is required in file'.__X_CALL_PAGE_FILE__);
        }
        $this->app_instance->run(__X_CALL_PAGE_FUNC__);
    }
    public function load_cfg() {
        global $_CFG;
        include_once(__X_FRAMEWORK_ROOT__ . '/config.default.php');
        $this->cfg = $_CFG;
        $cfg_db = $this->cfg->db;
        $cfg_tpl = $this->cfg->tpl;
        if(file_exists(__X_APP_ROOT__. '/data/conf/config.php')) {
            include_once(__X_APP_ROOT__ . '/data/conf/config.php');
            if($this->cfg !== $_CFG) {
                throw new XException('Can not initialize $_CFG in '.__X_APP_ROOT__.'/data/config.php');
            }
            if($cfg_db !== $_CFG->db) {
                throw new XException('Can not initialize $_CFG->db in '.__X_APP_ROOT__.'/data/config.php');
            }
            if($cfg_tpl !== $_CFG->tpl) {
                throw new XException('Can not initialize $_CFG->tpl in '.__X_APP_ROOT__.'/data/config.php');
            }
        }
    }
    public function set_time_zone() {
        if(empty($this->cfg->timezone)) {
            throw new XException('Application timezone unset in config file ');
        }
        date_default_timezone_set($this->cfg->timezone);
    }
}
